//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __MODULE_H__
#define __MODULE_H__

class CModule;
class Section;
class CLoadedFile;

class Section : public VDataSource
{
public:
    CModule         *m_pOwner;
    char            m_szName[9];

    UInt32          m_uVAddr;
    UInt32          m_uVSize;
    UInt32          m_dwProtect;
    UInt32          m_uPointerToRawData;
    UInt32          m_uSizeOfRawData;
    CLoadedFile     *m_pFile;

public:
    void Initialize(CModule * pModule)
    {
        m_pOwner = pModule;
        m_szName[8] = 0;
        m_dwProtect = 0;
        m_pFile     = NULL;
    }

    ~Section();

    PPage * GetPage(UInt32 uOffset);
    ECode Flush();

    ECode MemAlloc(Boolean bNeedContMem);
    ECode MemFree();

    Boolean RelocAddr(UInt32 vAddr, UInt32 uOffset, UInt32 uType);

    void MemZero() { m_cache.MemZero(); }
    void MemCopy(void * p, int nSize) { m_cache.MemCopy(p, nSize); }
    void MemCopy(UInt32 uOffset, UInt32 uSize, void * p)
    {
        m_cache.MemCopy(uOffset, uSize, p);
    }

    void SetAddr(UInt32 uAddr)
    {
        assert((uAddr & ~PAGE_MASK) == 0);
        m_uVAddr = uAddr;
    }

    void SetSize(UInt32 uSize)
    {
        assert(uSize != 0);
        m_uVSize = RoundUp2(uSize, PAGE_SIZE);
    }
};

class CModule : public DLinkNode
{
// member functions
//
public:
    UInt32 AddRef(void);
    UInt32 Release(void);

    void * GetExportKAddress();
    void * GetImportKAddress();

    CModule();
    ~CModule();

// member variable
//
public:
    wchar_t *       m_wszName;
    wchar_t *       m_wszFullPath;

    UInt32           m_uImageBase;
    UInt32          m_uTotalSize;
    UInt32          m_uRelocOffset;
    UInt32           m_uEntryPoint;

    UInt32          m_cSections;
    Section *       m_pSections;

    Section *       m_pExport;
    UInt32          m_uExportOffset;
    UInt32          m_uExportSize;

    Section *       m_pImport;
    UInt32          m_uImportOffset;
    UInt32          m_uImportSize;

    Section *       m_pResource;

    DLinkNode       m_rModuleList;

#ifdef _ELADBGAGENT
    PByte           m_pImgDebugDirEntry;
#endif

    friend void GUnloadModule(CModule * pModule);
    friend CModule * FindModule(const wchar_t * wszName);
protected:
    Interlocked     m_cRef;
};

inline CModule::CModule() :
    m_wszName(NULL),
    m_wszFullPath(NULL),
    m_uImageBase(0),
    m_pSections(NULL),
    m_pExport(NULL),
    m_pImport(NULL),
    m_pResource(NULL)
{
#ifdef _ELADBGAGENT
    m_pImgDebugDirEntry = NULL;
#endif

    m_rModuleList.Initialize();
}

//
// Get kernel started address of export section.
//
inline void * CModule::GetExportKAddress()
{
    return __VA(((PPage *)
        (m_pExport->m_cache.m_pagesList.m_pNext))->m_uAddr + m_uExportOffset);
}

//
// Get kernel started address of import section.
//
inline void * CModule::GetImportKAddress()
{
    return __VA(((PPage *)
        (m_pImport->m_cache.m_pagesList.m_pNext))->m_uAddr + m_uImportOffset);
}

struct ModuleRef : public DLinkNode
{
    CModule *        m_pModule;

    ModuleRef(CModule *pModule) : m_pModule(pModule) { }
};

typedef enum ModuleFileType {
    ModuleFileType_EXE  = 0,
    ModuleFileType_DLL  = 0x2000, // equal to IMAGE_FILE_DLL (in peimage.h)
    ModuleFileType_MARK = 0x2000
} ModuleFileType;

extern ECode GLoadModuleA(
    const char *szName,
    UInt32 dwFlags,
    ModuleFileType  modFileType,
    CModule ** ppModule);

extern ECode GLoadModuleW(
    const wchar_t *wszName,
    UInt32 dwFlags,
    ModuleFileType  modFileType,
    CModule ** ppModule);

extern void GUnloadModule(
    CModule * pModule);

extern UInt32 GetExportAddressByName(
        CModule * pModule,
        const char * pszName);

extern UInt32 GetExportAddressByOrdinal(
        CModule * pModule,
        UInt32 uOrdinal);

#endif // __MODULE_H__
